package com.xxdh.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.xxdh.domain.dto.CourseDto;
import com.xxdh.domain.po.Course;
import com.xxdh.domain.po.StudentCourseRelation;
import com.xxdh.domain.vo.CourseVo;
import com.xxdh.exception.BusiException;
import com.xxdh.mapper.StudentCourseRelationMapper;
import com.xxdh.service.ICourseService;
import com.xxdh.service.IStudentCourseRelationService;
import com.xxdh.service.ITeacherCourseService;
import com.xxdh.util.ResultConstants;
import com.xxdh.util.UserHolder;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.LongStream;

@Service
@RequiredArgsConstructor
public class CourseServiceImpl implements ICourseService {
    private final ITeacherCourseService teacherCourseService;
    private final IStudentCourseRelationService studentCourseService;
    private final StudentCourseRelationMapper studentCourseRelationMapper;

    /**
     * 添加课程
     * @param courseDto 课程信息
     */
    @Override
    public void addCourse(CourseDto courseDto) {
        // 1.判断是否有冲突
        List<Course> courses = teacherCourseService.lambdaQuery().eq(Course::getWeekDay, courseDto.getWeekDay()).list();
        List<Course> courseList = courses.stream().
                filter(course -> course.getStartTime() >= courseDto.getStartTime() && course.getEndTime() <= courseDto.getEndTime()).
                collect(Collectors.toList());
        if(CollUtil.isNotEmpty(courseList)){
            throw new BusiException(ResultConstants.COURSE_CONFLICT);
        }
        // 2.添加课程信息
        Course course = BeanUtil.copyProperties(courseDto, Course.class);
        teacherCourseService.save(course);
    }

    /**
     * 删除课程
     * @param courseId 课程id
     */
    @Override
    public void deleteCourseByCourseId(String courseId) {
        // 1.删除课程信息
        teacherCourseService.removeById(Long.valueOf(courseId));
        // 2.删除课程对应的学生课表信息
        List<StudentCourseRelation> studentCoursRelations = studentCourseService.lambdaQuery().eq(StudentCourseRelation::getCourseId, courseId).list();
        if(studentCoursRelations == null || studentCoursRelations.size() == 0) {
            return;
        }
        // 2.1批量删除学生课表信息
        List<Long> studentCourseIds = studentCoursRelations.stream().map(StudentCourseRelation::getId).collect(Collectors.toList());
        // 2.2删除学生课表信息
        studentCourseService.removeBatchByIds(studentCourseIds);
    }

    /**
     * 获取老师课程列表
     * @return
     */
    @Override
    public List<Course> getCourseListByTeacherId(Long teacherId) {
        // 获取课程信息
        List<Course> courses = teacherCourseService.lambdaQuery().eq(Course::getTeacherId, teacherId).list();
        return courses;
    }

    /**
     * 获取学生课程列表
     * @return
     */
    @Override
    public Map<String, List<CourseVo>> getCourseListByUserId() {
        // 1.获取学生id
        Long userId = UserHolder.getUserId();
        // 2.获取学生选课信息
        List<StudentCourseRelation> list = studentCourseService.lambdaQuery().eq(StudentCourseRelation::getStudentId, userId).list();
        if(CollUtil.isEmpty(list)) {
            return new HashMap<>();
        }
        List<Course> courses = list.stream().map(studentCourse -> teacherCourseService.lambdaQuery().
                eq(Course::getId, studentCourse.getCourseId()).one()).collect(Collectors.toList());
        List<CourseVo> courseInfos = courses.stream().map(course -> CourseVo.builder().courseId(course.getId().toString()).courseName(course.getCourseName()).
                location(course.getLocation()).startTime(course.getStartTime()).
                endTime(course.getEndTime()).weekDay(course.getWeekDay().toString()).build()).collect(Collectors.toList());
        Map<String, List<CourseVo>> collect = courseInfos.stream().collect(Collectors.groupingBy(CourseVo::getWeekDay));
        return collect;
    }

    /**
     * 学生选课
     * @param courseId 课程id
     */
    @Override
    public void selectCourse(String courseId) {
        // 1.获取学生id
        Long userId = UserHolder.getUserId();
        // 2.判断学生是否已经选过该课程或者时间冲突
        // 2.1获取学生已选课程ids
        List<StudentCourseRelation> studentCoursRelations = studentCourseService.lambdaQuery().eq(StudentCourseRelation::getStudentId, userId).list();
        List<Long> courseIds = studentCoursRelations.stream().map(studentCourse -> studentCourse.getCourseId()).collect(Collectors.toList());
        if(CollUtil.isNotEmpty(courseIds)){
            // 2.2获取课程信息
            Course course = teacherCourseService.lambdaQuery().eq(Course::getId, Long.valueOf(courseId)).one();
            // 2.3判断时间是否冲突
            List<Course> courses = teacherCourseService.listByIds(courseIds);
            List<Course> courseList = courses.stream().filter(c -> c.getWeekDay() == course.getWeekDay()
                    && c.getStartTime() != course.getStartTime()
                    && c.getEndTime() != course.getEndTime()).collect(Collectors.toList());
            if(CollUtil.isNotEmpty(courseList)){
                throw new BusiException(ResultConstants.SELECT_COURSE_CONFLICT);
            }
        }
        // 3.插入学生选课记录
        StudentCourseRelation studentCourseRelation = StudentCourseRelation.builder().studentId(userId).courseId(Long.valueOf(courseId)).build();
        studentCourseService.save(studentCourseRelation);
    }

    @Override
    public List<Long> getStudentIdListByTeacherId(Long teacherId) {
        List<Course> courses = getCourseListByTeacherId(teacherId);
        List<Long> courseIds = courses.stream().map(course -> course.getId()).collect(Collectors.toList());
        List<Long> studentIds = studentCourseRelationMapper.selectStudentIdListByCourseIdList(courseIds);
        return studentIds;
    }

    /**
     * 获取课程信息
     * @param courseId
     * @return
     */
    @Override
    public Course getCourseById(Long courseId) {
        return teacherCourseService.getById(courseId);
    }

    /**
     * 获取课程对应的学生id列表
     * @param courseId 课程id
     * @return
     */
    @Override
    public List<Long> getStudentIdListByCourseId(Long courseId) {
        List<Long> studentIds = studentCourseService.getStudentIdListByCourseId(courseId);
        return studentIds;
    }

    @Override
    public Map<String, List<CourseVo>> getCourseListMapByTeacherId(Long teacherId) {
        List<Course> courses = getCourseListByTeacherId(teacherId);
        if(CollUtil.isEmpty(courses)){
            return new HashMap<>();
        }
        List<CourseVo> courseInfos = courses.stream().map(course -> CourseVo.builder().courseId(course.getId().toString()).courseName(course.getCourseName()).
                location(course.getLocation()).startTime(course.getStartTime()).
                endTime(course.getEndTime()).weekDay(course.getWeekDay().toString()).build()).collect(Collectors.toList());
        Map<String, List<CourseVo>> collect = courseInfos.stream().collect(Collectors.groupingBy(CourseVo::getWeekDay));
        return collect;
    }

    @Override
    public List<CourseVo> getNotSelectedCourseListByStudentId(Long userId) {
        List<Course> notSelectedCourseList = new ArrayList<>();
        List<StudentCourseRelation> studentCourseRelations = studentCourseService.lambdaQuery().eq(StudentCourseRelation::getStudentId, userId).list();
        // 获取已选课程ids
        List<Long> courseIdList = studentCourseRelations.stream().map(studentCourseRelation -> studentCourseRelation.getCourseId()).collect(Collectors.toList());
        // 获取所有课程
        List<Course> courses = teacherCourseService.getBaseMapper().selectList(null);
        // 获取未选课程
        if(CollUtil.isEmpty(courses)){
            return new ArrayList<>();
        }
        notSelectedCourseList = courses.stream().filter(course -> !courseIdList.contains(course.getId())).collect(Collectors.toList());
        List<CourseVo> collect = notSelectedCourseList.stream().map(course -> CourseVo.builder().courseId(course.getId().toString()).courseName(course.getCourseName()).location(course.getLocation()).startTime(course.getStartTime()).endTime(course.getEndTime()).weekDay(course.getWeekDay().toString()).build())
                .collect(Collectors.toList());
        return collect;
    }


}
